package com.ajk.server.service.impl;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.ajk.server.dao.NurseStationDictMapper;
import com.ajk.server.dao.UsersMapper;
import com.ajk.server.exception.AjkException;
import com.ajk.server.exception.ErrorConstant;
import com.ajk.server.model.NurseStationDict;
import com.ajk.server.model.Users;
import com.ajk.server.model.query.NurseStationDictQuery;
import com.ajk.server.service.NurseStationDictService;
import com.ajk.server.utils.AjkUtil;
import com.ajk.server.utils.HttpClientUtil;
import com.ajk.server.utils.LocationUtil;
import com.ajk.server.utils.RedisKeyUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 护士站  <br>
 * dict_nurse_station <br>
 * v1.0 2016-05-01
 */
 @Service
 public class NurseStationDictServiceImpl implements NurseStationDictService {
	
	private static final Logger logger = LoggerFactory.getLogger(NurseStationDictServiceImpl.class);
	
	@Autowired
	private NurseStationDictMapper nurseStationDictMapper;
	
	@Autowired
	private RedisTemplate<String, Object> template;
	
	@Autowired
	private UsersMapper usersMapper;
	
	@Autowired
	private Environment env;
	
	/**
 	*根据ID删除 护士站
 	*/
 	@Override
 	public Integer deleteNurseStationDictById(Integer id){
 		return nurseStationDictMapper.deleteById(id);
 	}
 	
 	/**
 	*新增 护士站
 	*/
 	@Override
 	@Transactional
 	public Integer batchInsertNurseStationDict(List<? extends NurseStationDict> nurseStationDicts){
		Integer count = nurseStationDictMapper.batchInsert(nurseStationDicts);
		return count;
 	}
 	/**
 	*新增 护士站
 	*/
 	@Override
 	@Transactional
 	public Integer insertNurseStationDict(NurseStationDict domain){
 		verifyLon(domain);
		nurseStationDictMapper.insert(domain);
		
		Integer id = domain.getId();
		
		syncSingletonRedis(id);
		
		return id;
 	}
 	
 	private void verifyLon(NurseStationDict domain){
 		if(domain.getLongitude() == null){
 			throw new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"经度不能为空");
 		}
 		if(domain.getLatitude() == null){
 			throw new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"纬度不能为空");
 		}
 		String[] lons = domain.getLongitude().toString().split("\\.");
 		if(lons[0].length() > 4 || lons[1].length()> 6){
 			throw new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"经度小数点前最大为四位,小数点后最大为六位,请检查");
 		}
 		String[] lats = domain.getLatitude().toString().split("\\.");
 		if(lats[0].length() > 4 || lats[1].length()> 6){
 			throw new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"纬度小数点前最大为四位,小数点后最大为六位,请检查");
 		}
 	}
 	/**
 	*更新 护士站
 	*/
 	@Override
 	@Transactional
 	public Integer updateNurseStationDict(NurseStationDict domain){
 		if(domain.getInUsed() == null){
 			verifyLon(domain);
 		}
		nurseStationDictMapper.update(domain);
		
		Integer id = domain.getId();
		
		syncSingletonRedis(id);
		
		return id;
 	}
 	
 	/**
 	*根据ID查询 护士站
 	*/
 	public NurseStationDict findNurseStationDictById(Integer id){
 		NurseStationDict result = nurseStationDictMapper.findById(id);
 		if(result!=null){
 			result.dealWith();
 		}
 		return result;
 	}

	/**
 	*通过query 查询 护士站
 	*/
	public List<NurseStationDict> findNurseStationDictByQuery(NurseStationDictQuery query){
		query.dealWith();
		List<NurseStationDict> result = nurseStationDictMapper.findByQuery(query);
		if(CollectionUtils.isNotEmpty(result)) {
			for (NurseStationDict nurseStationDict : result) {
				nurseStationDict.dealWith();
			}
		}
		Collections.sort(result);
		return result;
	}	
	
	/**
 	*通过query count总条数
 	*/
 	public Integer countNurseStationDictByQuery(NurseStationDictQuery query){
 		query.dealWith();
 		Integer result = nurseStationDictMapper.countByQuery(query);
 		return result;
 	}
 	
 	/**
 	* 通过ids查询
 	*/
 	public List<NurseStationDict> findNurseStationDictByIds(List<Integer> ids){
 		List<NurseStationDict> result = nurseStationDictMapper.findByIds(ids);
		if(CollectionUtils.isNotEmpty(result)) {
			for (NurseStationDict nurseStationDict : result) {
				nurseStationDict.dealWith();
			}
		}
		return result;
 	}
 	
 	/**
 	*根据name查询 身体部位
 	*/
	public NurseStationDict findByName(String name){
		NurseStationDict result = nurseStationDictMapper.findByName(name);
 		if(result!=null){
 			result.dealWith();
 		}
 		return result;
	}
	
	/**
 	*获取所有字典 身体部位
 	*/
	public List<NurseStationDict> findAll(){
		List<NurseStationDict> result = nurseStationDictMapper.findAll();
		if(CollectionUtils.isNotEmpty(result)) {
			for (NurseStationDict nurseStationDict : result) {
				nurseStationDict.dealWith();
			}
		}
		return result;
	}
	
	@Override
	public List<NurseStationDict> findNurseStationDictOrderByDistince(NurseStationDictQuery query) {
		
		List<NurseStationDict> list = findAllInCache();
		
		List<NurseStationDict> result = new ArrayList<>();
		//经度
		Double longitude = query.getLongitude();
		//纬度
		Double latitude = query.getLatitude();

		if (CollectionUtils.isNotEmpty(list)) {
			for (NurseStationDict nurseStationDict : list) {
				dealWithDistince(longitude, latitude, nurseStationDict);
			}
			Collections.sort(list,new Comparator<NurseStationDict>() {

				@Override
				public int compare(NurseStationDict o1, NurseStationDict o2) {
					if(o1!=null && o2!=null && o1.getDistance()!=null && o2.getDistance()!=null){
						return o1.getDistance().compareTo(o2.getDistance());
					}
					return 0;
				}
			});
			Integer start = query.getStart();
			Integer limit = query.getLimit();
			if(start==null || start<0 ){
				start = 0 ;
			}
			if(limit==null || limit>list.size()){
				limit = list.size();
			}
			Integer end = start + limit;
			if(end>list.size()){
				end = list.size();
			}
			if(end >= start){
				result = list.subList(start, end);
			}
		}
		return result;
	}
	
	private void dealWithDistince(Double longitude,Double latitude,NurseStationDict dict){
		//经度
		Double _longitude = dict.getLongitude();
		//纬度
		Double _latitude = dict.getLatitude();
		
		if(_longitude!=null && _latitude!=null && longitude!=null && latitude!=null){
			double distance = LocationUtil.Distance(_longitude, _latitude, longitude, latitude);
			dict.setDistance(distance);
		}
	}
	
	public List<NurseStationDict> findAllInCache(){
		String key = RedisKeyUtil.nurseStationDictHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		HashOperations<String, String, NurseStationDict> operations = template.opsForHash();
		List<NurseStationDict> list = operations.values(key);	
		if (CollectionUtils.isNotEmpty(list)) {
			for (int i = list.size()-1; i >= 0; i--) {
				if(!(list.get(i) instanceof NurseStationDict)){
					list.remove(i);
				}
			}
		}
		return list;
	}

	@Override
	public void syncSingletonRedis(Integer nurseStationId) {
		String key = RedisKeyUtil.nurseStationDictHashKey();
		if(!template.hasKey(key)){
			syncInRedis(true);
		}
		String hashKey = RedisKeyUtil.domainIdKey(nurseStationId);
		HashOperations<String, String, NurseStationDict> operations = template.opsForHash();
		NurseStationDict dict = nurseStationDictMapper.findById(nurseStationId);
		if(dict != null && dict.getInUsed()==1){
			operations.put(key, hashKey, dict);
		}else if(operations.hasKey(key, hashKey)){
			operations.delete(key, hashKey);
		}
	}

	@Override
	public void syncInRedis(boolean force) {
		String key = RedisKeyUtil.nurseStationDictHashKey();
		if(force || !template.hasKey(key)){
			template.delete(key);
			List<NurseStationDict> all = findAll();
			if (CollectionUtils.isNotEmpty(all)) {
				Map<String, NurseStationDict> map = new HashMap<String, NurseStationDict>();
				for (NurseStationDict nurseStationDict : all) {
					String hashKey = RedisKeyUtil.domainIdKey(nurseStationDict.getId());
					map.put(hashKey, nurseStationDict);
				}
				if(!map.isEmpty()){
					template.opsForHash().putAll(key, map);
				}
			}
		}
	}

	@Override
	public void bindNurseStation(Integer userId, Integer nurseStationId) {
		Users users = new Users();
		users.setId(userId);
		users.setNursingStationId(nurseStationId);
		usersMapper.update(users);
	}

	@Override
	public JSONObject syncInRemote(Integer id) {
		logger.info("=========================准备同步护士站(id={})======================",id);
		JSONObject obj = null;
		NurseStationDict dict = nurseStationDictMapper.findById(id);
		if(dict!=null){
			String valicode= AjkUtil.getVaildate();
			
			String url = MessageFormat.format(env.getProperty("config.remote_sync_nurse_station_url"), valicode);
			
			HashMap<String, Object> parameterMap = new HashMap<>();
			parameterMap.put("name", dict.getName());
			parameterMap.put("tel", dict.getTel());
			parameterMap.put("address", dict.getAddress());
			parameterMap.put("region_id", dict.getRegionId());
			parameterMap.put("longitude", dict.getLongitude());
			parameterMap.put("latitude", dict.getLatitude());
			parameterMap.put("in_used", dict.getInUsed());
			boolean needUpdateOnlyCode = true;
			if(StringUtils.isNotEmpty(dict.getOnlycode())){
				parameterMap.put("onlycode", dict.getOnlycode());
				needUpdateOnlyCode = false;
			}
			try {
				logger.info("同步护士站url如下:\n{}\n参数如下:\n{}\n",url,JSON.toJSONString(parameterMap));
				String result = HttpClientUtil.doFormPost(url, parameterMap);
				logger.info("同步结果：\n{}",result);
				obj = JSON.parseObject(result);
				if(needUpdateOnlyCode && obj.containsKey("onlycode")){
					dict.setOnlycode(obj.getString("onlycode"));
					nurseStationDictMapper.update(dict);
				}
				
			} catch (Exception e) {
				logger.error("同步护士站失败",e);
			}
			syncSingletonRedis(id);
		}
		return obj;
	}
	
	
	
}	